package by.gamedev.site.client.app;

import java.util.logging.Level;
import java.util.logging.Logger;

import by.gamedev.site.client.app.activity.IsGameDevMobileActivity;
import by.gamedev.site.client.app.place.GameDevPlaceHistoryMapper;
import by.gamedev.site.client.app.place.PlaceHistoryFactory;
import by.gamedev.site.client.app.place.ProxyListPlace;
import by.gamedev.site.client.app.place.ProxyListPlacePicker;
import by.gamedev.site.client.app.place.ProxyPlaceToListPlace;
import by.gamedev.site.client.managed.activity.GameDevMobileActivities;
import by.gamedev.site.client.managed.request.ApplicationRequestFactory;
import by.gamedev.site.client.style.MobileListResources;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ValuePicker;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

/**
 * Mobile application for browsing entities.
 */
public class GameDevMobileApp extends GameDevApp {

    /**
     * The root activity that shows all entities.
     */
    private static class DefaultActivity extends AbstractActivity implements IsGameDevMobileActivity {

        private final Widget widget;

        public DefaultActivity(final Widget widget) {
            this.widget = widget;
        }

        @Override
        public void start(final AcceptsOneWidget panel, final EventBus eventBus) {
            panel.setWidget(widget);
        }

        @Override
        public Place getBackButtonPlace() {
            return null;
        }

        @Override
        public String getBackButtonText() {
            return null;
        }

        @Override
        public Place getEditButtonPlace() {
            return null;
        }

        @Override
        public String getTitleText() {
            return "All Entities";
        }

        @Override
        public boolean hasEditButton() {
            return false;
        }
    }

    public static final Place          ROOT_PLACE = new Place() {
        //nothing
                                                  };

    private static MobileListResources res        = GWT.create(MobileListResources.class);

    /**
     * Get the list resources used for mobile.
     */
    public static MobileListResources getMobileListResources() {
        if(res == null ) {
            res = GWT.create(MobileListResources.class);
            res.cellListStyle().ensureInjected();
        }
        return res;
    }

    IsGameDevMobileActivity         lastActivity = null;

    static final Logger                     log          = Logger.getLogger(GameDev.class.getName());

    final GameDevMobileShell                shell;
    final GameDevMobileActivities   scaffoldMobileActivities;
  //TODO    private final ApplicationRequestFactory requestFactory;
    private final EventBus                  eventBus;
    final PlaceController           placeController;
    private final PlaceHistoryFactory       placeHistoryFactory;

    @Inject
    public GameDevMobileApp(final GameDevMobileShell shell, final ApplicationRequestFactory requestFactory, final EventBus eventBus,
            final PlaceController placeController, final GameDevMobileActivities scaffoldMobileActivities,
            final PlaceHistoryFactory placeHistoryFactory) {
        this.shell = shell;
      //TODO        this.requestFactory = requestFactory;
        this.eventBus = eventBus;
        this.placeController = placeController;
        this.scaffoldMobileActivities = scaffoldMobileActivities;
        this.placeHistoryFactory = placeHistoryFactory;

    }

    @Override
    public void run() {
        isMobile = true;

        /* Add handlers, setup activities */

        init();

        /* Hide the loading message */
        final Element loading = Document.get().getElementById("loading");
        loading.getParentElement().removeChild(loading);

        /* And show the user the shell */

        // TODO(jlabanca): Use RootLayoutPanel when we switch to DockLayoutPanel.
        RootPanel.get().add(shell);
    }

    private void init() {

        GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() {
            @Override
            public void onUncaughtException(final Throwable e) {
                Window.alert("Error: " + e.getMessage());
                log.log(Level.SEVERE, e.getMessage(), e);
            }
        });
//TODO
        /*
        final Receiver<UserInformationProxy> receiver = new Receiver<UserInformationProxy>() {
            @Override
            public void onSuccess(final UserInformationProxy userInformationProxy) {
                shell.getLoginWidget().setUserInformation(userInformationProxy);
            }
        };
        */
        // TODO
        /*
         * requestFactory.userInformationRequest().getCurrentUserInformation(Window.Location.getHref()).fire(receiver);
         * 
         * if(LogConfiguration.loggingIsEnabled() ) { // Add remote logging handler final RequestFactoryLogHandler.LoggingRequestProvider provider =
         * new RequestFactoryLogHandler.LoggingRequestProvider() {
         * 
         * @Override public LoggingRequest getLoggingRequest() { return requestFactory.loggingRequest(); } }; Logger.getLogger("").addHandler(new
         * RequestFactoryLogHandler(provider, Level.WARNING, new ArrayList<String>())); }
         */
        /* Left side lets us pick from all the types of entities */

        // TODO final Renderer<ProxyListPlace> placePickerRenderer = new ApplicationListPlaceRenderer();
        final Cell<ProxyListPlace> placePickerCell = new AbstractCell<ProxyListPlace>() {
            @Override
            public void render(final ProxyListPlace value, final Object viewData, final SafeHtmlBuilder sb) {
                // TODO sb.appendEscaped(placePickerRenderer.render(value));
            }
        };
        final CellList<ProxyListPlace> placePickerList = new CellList<ProxyListPlace>(placePickerCell, getMobileListResources());
        placePickerList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
        final ValuePicker<ProxyListPlace> placePickerView = new ValuePicker<ProxyListPlace>(placePickerList);
        final Activity defaultActivity = new DefaultActivity(placePickerView);
        final ProxyPlaceToListPlace proxyPlaceToListPlace = new ProxyPlaceToListPlace();
        final ProxyListPlacePicker proxyListPlacePicker = new ProxyListPlacePicker(placeController, proxyPlaceToListPlace);
        placePickerView.setAcceptableValues(getTopPlaces());
        proxyListPlacePicker.register(eventBus, placePickerView);

        /*
         * Wrap the scaffoldMobileActivities so we can intercept activity requests and remember the last activity (for back button support).
         */

        scaffoldMobileActivities.setRootActivity(defaultActivity);
        final ActivityMapper activityMapper = new ActivityMapper() {
            @Override
            public Activity getActivity(final Place place) {
                // Defer to scaffoldMobileActivities.
                final Activity nextActivity = scaffoldMobileActivities.getActivity(place);

                // Clear the value of the placePicker so we can select a new top level
                // value.
                placePickerView.setValue(null, false);

                // Update the title, back and edit buttons.
                final Button backButton = shell.getBackButton();
                if(nextActivity instanceof IsGameDevMobileActivity ) {
                    lastActivity = (IsGameDevMobileActivity) nextActivity;

                    // Update the title.
                    shell.setTitleText(lastActivity.getTitleText());

                    // Update the back button.
                    final String backButtonText = lastActivity.getBackButtonText();
                    if(backButtonText == null || backButtonText.length() == 0 ) {
                        shell.setBackButtonVisible(false);
                    } else {
                        shell.setBackButtonVisible(true);
                        backButton.setText(backButtonText);
                    }

                    // Update the edit button.
                    shell.setEditButtonVisible(lastActivity.hasEditButton());
                } else {
                    lastActivity = null;
                    shell.setTitleText("");
                    shell.setBackButtonVisible(false);
                    shell.setEditButtonVisible(false);
                }

                // Return the activity.
                return nextActivity;
            }
        };

        /*
         * The body is run by an ActivityManager that listens for PlaceChange events and finds the corresponding Activity to run
         */

        final ActivityManager activityManager = new ActivityManager(activityMapper, eventBus);

        activityManager.setDisplay(shell.getBody());

        /* Browser history integration */
        final GameDevPlaceHistoryMapper mapper = GWT.create(GameDevPlaceHistoryMapper.class);
        mapper.setFactory(placeHistoryFactory);
        final PlaceHistoryHandler placeHistoryHandler = new PlaceHistoryHandler(mapper);
        placeHistoryHandler.register(placeController, eventBus, ROOT_PLACE);
        placeHistoryHandler.handleCurrentHistory();

        shell.getBackButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(final ClickEvent event) {
                if(lastActivity != null ) {
                    final Place backPlace = lastActivity.getBackButtonPlace();
                    if(backPlace != null ) {
                        placeController.goTo(backPlace);
                    }
                }
            }
        });
        shell.getEditButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(final ClickEvent event) {
                if(lastActivity != null ) {
                    final Place editPlace = lastActivity.getEditButtonPlace();
                    if(editPlace != null ) {
                        placeController.goTo(editPlace);
                    }
                }
            }
        });
    }
}
